//****************************************************************************
//
//	Simple RFID Sample Code For Win32
//
//	Author: Jim Peternel 2008
//
//	Copyright 2008 Intermec Technologies Corp.
//
//  The purpose of this code is to show how to use the various methods in the IDL.
//  This sample code is not meant to be used as a demo program.
//
//  To use this sample code you must download an install the RFID resource kit from
//  www.intermec.com
//
//****************************************************************************

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Intermec.DataCollection.RFID;

namespace SimpleRFIDApp
{
    public partial class Form1 : Form
    {
        //define reader object
        public BRIReader brdr = null;
        
        private string[] MyTagList = new string[100];
        private bool bReaderOffLine = true;
        private int iTagCount = 0;

        public Form1()
        {
            InitializeComponent();
        }

        private bool OpenReaderConnection()
        {
            //Establish connection with reader.
            //Choose network or serial connection.

            bool bStatus = false;
            string sMsg = null;
            string sConnection = null;

            //define connection
            //string sConnection = "SERIAL://COM1";
            //string sConnection = "TCP://192.168.1.1";
            if (radioButton1.Checked == true)
            {
                //serial
                sConnection = textBox1.Text;
            }
            else
            {
                //tcpip
                sConnection = textBox2.Text;
            }
            
            //optional: enable IDL debug logging *******************************
            BRIReader.LoggerOptionsAdv LogOp = new BRIReader.LoggerOptionsAdv();
            LogOp.LogFilePath = ".\\IDLClassDebugLog.txt";
            LogOp.ShowNonPrintableChars = true;
            //******************************************************************

            try
            {
                //option 1: open reader connection simple method, no debugging
                brdr = new BRIReader(this, sConnection);

                //option two -> set size of reader buffer, event buffer, and enable IDL logging.
                //Reader Buffer is used for storing tags when you issue a READ, or READ REPORT=NO
                //Event Buffer is used for storing tags when you issue a READ REPORT=EVENT and all other events.
                //BRIReader(this, sConnection, Reader Buffer, Event Buffer, LogOp);
                //this.brdr = new BRIReader(this, sConnection, 1000, 1000, LogOp);

                bStatus = true;
            }
            catch (BasicReaderException ex)
            {
                MessageBox.Show(ex.ToString());
                bStatus = false;
            }

            if (brdr == null || bStatus == false)
            {
                //failed to create reader connection
                bReaderOffLine = true;
                PostMessageToListBox1("Unable to connect to reader!");
                PostMessageToListBox1(sConnection);
                return false;
            }
        
            //Verify that we are actually talking to the RF module.  Should return OK>
            sMsg = this.brdr.Execute("PING");
            if (sMsg != null)
            {
                if (sMsg.Equals("OK>"))
                {
                    //get reader firmware version
                    sMsg = this.brdr.Execute("VER");
                    ParseResponseMessage(sMsg);

                    SetReaderAttributes();
                    bReaderOffLine = false;
                    bStatus = true;
                }
            }

            if (bStatus == false)
            {
                //not connected to reader
                PostMessageToListBox1("Unable to connect to hand held");
                PostMessageToListBox1(sConnection);
                bReaderOffLine = true;
            }

            return bStatus;
        }

        private void ParseResponseMessage(string sMsg)
        {
            //parse the response from the reader.
            //Some responses have multiple lines, such as the reponse
            //to the VERSION command (VER).  Lines separated by \r\n.

            int x = 0;
            string delimStr = null;
            string[] tList = null;
            char[] delimiter = null;
            int RspCount = 0;

            delimStr = "\n";
            delimiter = delimStr.ToCharArray();
            tList = sMsg.Replace("\r\n", "\n").Split(delimiter);
            RspCount = tList.Length;
            for (x = 0; x < RspCount; x++)
            {
                PostMessageToListBox1(tList[x]);
            }
        }

        private void SetReaderAttributes()
        {
            //Optional Code
            //Some examples of how to set attributes
            string sRsp = null;
            
            try
            {

                brdr.Execute("ATTRIB IDTRIES=1");
                brdr.Execute("ATTRIB ANTTRIES=1");
                brdr.Execute("ATTRIB WRTRIES=3");
                brdr.Execute("ATTRIB ANTS=1");

                //Other examples of selecting antennas
                //brdr.Execute("ATTRIB ANTS=1,2,3,4");
                //brdr.Execute("ATTRIB ANTS=2,4");
                //brdr.Execute("ATTRIB ANTS=1,3,4");

                //get the list of all attributes from the reader and display them.
                sRsp = this.brdr.Execute("ATTRIB");
                ParseResponseMessage(sRsp);
            }
            catch (Intermec.DataCollection.RFID.BasicReaderException ex)
            {
                MessageBox.Show("SetAttribute Exception : " + ex.Message);
            }
        }

        private void SetTriggers()
        {
            //Optional Code
            //You need to delete the triggers when you exit your app otherwise they will 
            //still be running after you disconnect.

            string sMsg = null;

            //delete any existing trigger definitions
            DeleteTriggers();

            //CREATE TRIGGERS
            sMsg = this.brdr.Execute("TRIGGER \"SensorON\" GPIOEDGE 1 1 FILTER 0");
            sMsg = this.brdr.Execute("TRIGGER \"SensorOFF\" GPIOEDGE 1 0 FILTER 0");
            PostMessageToListBox1("Triggers Created");
        }

        private void DeleteTriggers()
        {
            //Optional Code
            //You need to delete the triggers when you exit your app otherwise they will 
            //still be running after you disconnect.

            string sMsg = null;

            //CLEAR ALL MACROS AND TRIGGERS
            sMsg = this.brdr.Execute("TRIGGER RESET");
            PostMessageToListBox1("Triggers Delete");
        }

        private void PostMessageToListBox1(string sMsg)
        {
            //POST message to listbox1
            listBox1.Items.Add(sMsg);
            listBox1.SelectedIndex = listBox1.Items.Count - 1;
            listBox1.Refresh();
        }

        private void CloseReaderConnection()
        {
            //close reader connection by disposing of the object.
            if (brdr != null) 
            { 
                brdr.Dispose();
                brdr = null;
            }
        }

        private void READGPIO()
        {
            string smsg = null;
            smsg = brdr.Execute("readgpio");
            PostMessageToListBox1(smsg);
        }

        private void WRITEGPIO()
        {
            string smsg = null;
            smsg = brdr.Execute("writegpio=15");
            PostMessageToListBox1(smsg);
        }

        private void AddRFIDEventHandlers()
        {
            //add rfid event handlers.  There are a number of event handlers, this 
            //example app is only adding 3.
            brdr.EventHandlerBattery += new Battery_EventHandler(brdr_EventHandlerBattery);
            brdr.EventHandlerAntennaFault += new AntennaFault_EventHandler(brdr_EventHandlerAntennaFault);
            brdr.EventHandlerTag += new Tag_EventHandlerAdv(brdr_EventHandlerTag);
            brdr.EventHandlerGPIO += new GPIO_EventHandlerAdv(brdr_EventHandlerGPIO);
            brdr.EventHandlerRadio += new Radio_EventHandlerAdv(brdr_EventHandlerRadio);
        }

        void brdr_EventHandlerBattery(object sender, Battery_EventArgs EvtArgs)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        void brdr_EventHandlerAntennaFault(object sender, AntennaFault_EventArgs EvtArgs)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        void brdr_EventHandlerRadio(object sender, EVTADV_Radio_EventArgs EvtArgs)
        {
            //Mainly used for Europe, Duty Cycle events.  If reader module overheats
            //you will get a thermal event.
            PostMessageToListBox1("Radio Event: " + EvtArgs.ToString());
            PostMessageToListBox1("Radio Event: " + EvtArgs.RadioDutyCycleTimeleft.ToString());
        }

        void brdr_EventHandlerGPIO(object sender, EVTADV_GPIO_EventArgs EvtArgs)
        {
            //GPIO event has fired.  This happens only if you have created a trigger 
            //and it has been activated.

            PostMessageToListBox1("GPIO Event: " + EvtArgs.TriggerNameString);
            PostMessageToListBox1("GPIO State: " + EvtArgs.GPIOstate.ToString());

            //add your code here
            /*
            if (EvtArgs.TriggerName.Equals("myTrigNameA")) 
            { }
            else if(EvtArgs.TriggerName.Equals("myTrigNameB")) 
            { }
            */
        }

        void brdr_EventHandlerTag(object sender, EVTADV_Tag_EventArgs EvtArgs)
        {
            //Used with ReadTagsReportEvent() with BRIReader.TagReportOptions.EVENT
            //When using REPORT=EVENT, tags are returned only one time by the reader, the
            //first time that they are read.  If you stop the read and restart it, then the tags
            //we be reported again.

            string sTagData = EvtArgs.DataString.ToString();

            PostMessageToListBox1(sTagData);

            label1.Text = "Tag Count = " + iTagCount;
            label1.Refresh();

            //IF you are reading fields such as COUNT, ANT, TIME, RSSI, that data comes back as fields.
            //sTagData = EvtArgs.Tag.ToString();
            //for (int x = 0; x < EvtArgs.Tag.TagFields.ItemCount; x++)
            //{
            //    myFields[x] = EvtArgs.Tag.TagFields.FieldArray[x].DataString;
            //}
            //PostMessageToListBox1(iRFIDTagCount + ". " + sTagData);
            //label2.Text = "RFID Tag Count = " + iRFIDTagCount;
            //I'm not displaying field data, I'll leave that to you.

            //you must issues a READ STOP to turn off the RF when you are done reading.
            //normally you would not stop at this point but would continue collecting tags
            //but for this sample we are going to stop reading tags here.
            brdr.StopReadingTags();
        }

        private void ReadTagsReportDirect()
        {
            //Simple read

            bool bStatus = false;

            if (bReaderOffLine == true)
            {
                PostMessageToListBox1("Reader is offline");
                return;
            }

            iTagCount = 0;
            
            //Here are various read options
            //Pick one and comment out the other two
            
            //1. Simple read of epc id's
            bStatus = brdr.Read();
            
            //2. Read only tags who's epc id starts with hex 0102
            //bStatus = brdr.Read("HEX(1:4,2)=H0102");
            
            //3. Return the antenna that read the tag and the number of times each tag was read
            //bStatus = brdr.Read(null, "ANT COUNT");

            //get the tag ids
            LoadTagList();
        }

        private void ReadTagsReportNo()
        {
            //Continuous read using polling to retrieve tag list

            bool bStatus = false;

            if (bReaderOffLine == true)
            {
                PostMessageToListBox1("Reader is offline");
                return;
            }

            iTagCount = 0;

            //determine how much time you want before polling for tag list.
            //here it is set to 1 second
            timer1.Interval = 1000;

            //Here are various read options
            //Pick one and comment out the other two
            
            //1. Read epc id's
            //bStatus = brdr.StartReadingTags(null, null, BRIReader.TagReportOptions.POLL);
            
            //2. Use a filter to read only tags who's epc id starts with hex 0102
            bStatus = brdr.StartReadingTags("HEX(1:4,2)=H0102", null, BRIReader.TagReportOptions.POLL);
            
            //3. Return the antenna that read the tag and the number of times each tag was read
            //bStatus = brdr.StartReadingTags(null, "ANT COUNT", BRIReader.TagReportOptions.POLL);

            //enable timer to poll for tags
            timer1.Enabled = true;
        }

        private void ReadTagsReportEvent()
        {
            //Continuous Read which returns tags as events

            bool bStatus = false;

            if (bReaderOffLine == true)
            {
                PostMessageToListBox1("Reader is offline");
                return;
            }

            iTagCount = 0;

            //Here are various read options
            //Pick one and comment out the other two
            
            //1. Read epc id's
            bStatus = brdr.StartReadingTags(null, null, BRIReader.TagReportOptions.EVENT);
            
            //2. Use a filter to read only tags who's epc id starts with hex 0102
            //bStatus = brdr.StartReadingTags("HEX(1:4,2)=H0102", null, BRIReader.TagReportOptions.EVENT);
            
            //3. Return the antenna that read the tag and the number of times each tag was read
            //bStatus = brdr.StartReadingTags(null, "ANT COUNT", BRIReader.TagReportOptions.EVENT);
        }

        private void WriteTag()
        {
            string sRSP = null;

            if (bReaderOffLine == true)
            {
                PostMessageToListBox1("Reader is offline");
                return;
            }

            //Pick a method to use for writing tags.  Below or FOUR examples of different writing methods.
            //1. Issue simple write command to program the EPC code in a tag.  This write command will write to
            //all tags found.
            //sRSP = this.brdr.Execute("W EPCID=H110203040506070809101112");

            //2. Program an EPC code using a where clause to select a subgroup of tags.
            //sRSP = this.brdr.Execute("W EPCID=H010203040506070809101112 WHERE HEX(1:4,2)==H1122");

            //3. Issue simple write command which writes the ascii string "HI" to the tag.  This write command
            //will write to all tags found.
            sRSP = this.brdr.Execute("W STRING(0,8)=\"12345678\"");

            //4. Issue write command which writes the ascii string "HI" to the all tags using a where clauise to select
            //all tags that do not have "HI" already programmed into them.  This write command
            //will write to all matching the where clause.
            //sRSP = this.brdr.Execute("W STRING(1:4,2)=\"HI\" WHERE STRING(1:4,2)!=\"HI\"");

            ParseResponseMessage(sRSP);

            //you need to check the response to determine if the write was successful
            if (sRSP.IndexOf("WROK") > 0)
            {
                //write succeeded.  Add your code here.
                iTagCount++;
                label2.Text = "RFID Tag Write Count = " + iTagCount;
            }
            else if (sRSP.IndexOf("WRERR") > 0)
            {
                //Write failed.  Add your code here.

            }
            else if (sRSP.IndexOf("PVERR") > 0)
            {
                //Write failed. Tag has been protected.  Add your code here.

            }
            else if (sRSP.IndexOf("PWERR") > 0)
            {
                //Write failed, RF power too low usually means tag is too far away.  Add your code here.

            }
            else if (sRSP.IndexOf("ERR") > 0)
            {
                //catch any other type of error that could occur during the write operation.   Add your code here.

            }
            else if (sRSP.IndexOf("ERR") == 0)
            {
                //syntax error in command.  Add your code here.

            }
        }

        private void LoadTagList()
        {
            //load epc ids into a list
            //used with REPORT=N0... -> private void timer1_Tick(object sender, EventArgs e)
            //used with REPORT=DIRECT...default read method -> private int ReadTagsReportDirect(){}

            if (brdr.TagCount > 0)
            {
                foreach (Tag tt in brdr.Tags)
                {
                    MyTagList[++iTagCount] = tt.ToString();

                    if (tt.TagFields.ItemCount > 0)
                    {
                        foreach (TagField tf in tt.TagFields.FieldArray)
                        {
                            if (tf.Status < 0)
                            {
                                //code to handle read or write error on this field
                            }
                            else
                            {
                                //get field data such as ANT, COUNT, TIME, AFI, etc.
                                MyTagList[iTagCount] += " " + tf.ToString();
                            }
                        }
                    }
                    PostMessageToListBox1(MyTagList[iTagCount]);
                    label1.Text = "Tag Count = " + iTagCount;
                    label1.Refresh();
                }
            }
            else
            {
                PostMessageToListBox1("NO TAGS");
                label1.Text = "Tag Count = " + iTagCount;
                label1.Refresh();
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            //enabled by ReadTagsReportNo() function
            //timer used to poll for tags

            bool bStatus = false;

            if (bReaderOffLine == true) { return; }

            timer1.Enabled = false;
            
            bStatus = brdr.PollTags();

            //get the tag ids
            LoadTagList();

            //you must issues a READ STOP to turn off the RF when you are done reading.
            //normally you would not stop at this point but would continue to polling for tags
            //but for this sample we are going to stop reading tags here.
            brdr.StopReadingTags();

            //normally you would re-enable timer and continue polling for tags
            //timer1.Enabled = true;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //open reader connection

            bool bStatus = false;

            button1.Enabled = false;

            bStatus = OpenReaderConnection();

            if (bStatus == false)
            {
                //failed to connect to reader
                MessageBox.Show("Unable to connect to reader!");
                button1.Enabled = true;
            }
            else
            {
                //connected and all is ok
                
                //create IDL event handlers
                AddRFIDEventHandlers();

                PostMessageToListBox1("Reader online and ready");

                //enable READ button.
                button4.Enabled = true;
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            //close reader connection and exit application
            CloseReaderConnection();
            Dispose();
            Application.Exit();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //clear listbox1
            listBox1.Items.Clear();
            listBox1.Refresh();
            iTagCount = 0;
            label1.Text = "Tag Count = " + iTagCount;
        }

        private void button4_Click(object sender, EventArgs e)
        {
            //Read Button
            if (bReaderOffLine == true) 
            {
                PostMessageToListBox1("Reader is offline");
                return; 
            }

            //ReadTagsReportDirect();
            //ReadTagsReportEvent();
            //ReadTagsReportNo();
            
        }

        private void button5_Click(object sender, EventArgs e)
        {
            //required when using brdr.StartReadingTags()
            brdr.StopReadingTags();
        }

        private void button6_Click(object sender, EventArgs e)
        {
            WriteTag();
        }

        private void button7_Click(object sender, EventArgs e)
        {
            READGPIO();
            WRITEGPIO();
        }
    }
}